<template>
  <Card size="small" class="share-card">
    <template #title>
      共{{ shares.length }}支
      <router-link to="/share/indexes">
        <div class="index">
          <h4 :class="incomeAmount > 0 ? 'rise' : 'fall'">总收益 / {{ ((incomeAmount / orignalAmount) * 100).toFixed(2) }}%</h4>
          <div :class="incomeAmount > 0 ? 'rise' : ''">
            <b>{{ orignalAmount.toFixed(2) }} / {{ totalAmount.toFixed(2) }} / {{ incomeAmount.toFixed(2) }}</b>
          </div>
        </div>
        <div class="index" v-for="item of indexes">
          <h4 :class="item.changes > 0 ? 'rise' : 'fall'">{{ item.name }}</h4>
          <div :class="item.changes > 0 ? 'rise' : ''">
            <b>{{ item.index }}</b>
            <b>{{ item.changes }}</b>
            <b>{{ item.changeRatio }}%</b>
          </div>
        </div>
      </router-link>
    </template>
    <template #extra>
      <h3 v-if="countDownVisible">倒计时：{{ countDown }}</h3>
      <span class="btn-group">
        <Button @click="addShare"> <FileAddOutlined />添加 </Button>
        <Button type="primary" @click="$router.push('/share/profits')"><FundViewOutlined />收益</Button>
        <Button type="primary" danger @click="ClearDatas"> <DeleteOutlined />清理 </Button>
      </span>
    </template>
    <Table
      :rowKey="getRowKey"
      :expand-column-width="30"
      :columns="columns"
      @resizeColumn="resizeColumn"
      :scroll="{ x: 1000, y: tableHeight }"
      :pagination="false"
      :expandIconColumnIndex="-1"
      :data-source="shares"
      @expand="onExpand"
      size="small"
      bordered>
      <template #bodyCell="{ column, record }">
        <span v-if="column.key == 'Name'">
          <Button type="link" size="small" @click="onDetail(record)">{{ record.Name }} / {{ record.Code.substring(2) }}</Button>
        </span>
        <span v-if="column.key == 'op'" class="btn-group">
          <Button type="primary" size="small" @click="onEdit(record)"> <EditFilled /></Button>
          <Button type="primary" size="small" danger @click="removeShare(record.Code)"> <DeleteOutlined /></Button>
        </span>
      </template>
      <template #expandedRowRender="{ record }">
        <div style="margin: 0">
          <sharePrice :code="record.Code" />
        </div>
      </template>
    </Table>
  </Card>
  <Modal v-model:visible="showEdit" title="编辑" :width="450" @ok="saveShare">
    <Form :label-col="{ style: { width: '100px' } }">
      <Form.Item class="Item" label="股票代码">
        <Input v-model:value="info.Code" :disabled="!isAddMode" />
      </Form.Item>
      <Form.Item class="Item" label="股票名称">
        <Input v-model:value="info.Name" :disabled="!isAddMode" />
      </Form.Item>
      <Form.Item class="Item" label="关注日期">
        <DatePicker v-model:value="info.CreatedOn" format="YYYY-MM-DD" :disabled="!isAddMode" />
      </Form.Item>
      <Form.Item class="Item" label="购买日期">
        <DatePicker v-model:value="info.PurchaseOn" format="YYYY-MM-DD" />
        <Button type="primary" danger shape="round" @click="resetShare(info)" style="margin-left: 10px"><RestOutlined /> 已卖出</Button>
      </Form.Item>
      <Form.Item class="Item" label="购买价格">
        <Input v-model:value="info.PurchasePrice" allowClear />
      </Form.Item>
      <Form.Item class="Item" label="购买数量">
        <Input v-model:value="info.PurchaseQuantity" allowClear />
      </Form.Item>
    </Form>
  </Modal>
</template>

<script setup>
  import dayjs from 'dayjs';

  import { useStore } from 'vuex';
  import { useRouter } from 'vue-router';

  import { h, ref, reactive, inject, markRaw, computed, onMounted, onUnmounted } from 'vue';
  import { Card, Table, Button, Modal, Form, Input, DatePicker } from 'ant-design-vue';
  import { EditFilled, FundViewOutlined, FileAddOutlined, DeleteOutlined, RestOutlined } from '@ant-design/icons-vue';

  import refresher from '@/libs/autoRefreshShares';
  import sharePrice from './components/SharePrices.vue';

  const $store = useStore();
  const $router = useRouter();

  const $http = inject('$http');
  const $modal = inject('$modal');
  const $message = inject('$message');
  const $eventBus = inject('$eventBus');

  const orignalAmount = ref(0);
  const totalAmount = ref(0);
  const incomeAmount = ref(0);

  const columns = [
    Table.EXPAND_COLUMN,
    {
      title: '名称',
      dataIndex: 'Name',
      key: 'Name',
      width: 150,
      ellipsis: true,
      resizable: true
    },
    {
      title: '关注日期 | 价格 | 涨幅',
      dataIndex: 'CreatedOn',
      width: 200,
      ellipsis: true,
      resizable: true,
      customRender: ({ record }) => {
        let beginPrice = record.BeginPrice;
        let currentPrice = record.CurrentPrice;
        let rate = (((currentPrice - beginPrice) / beginPrice) * 100).toFixed(2);

        return h('div', { class: 'complexs' }, [
          h('span', record.CreatedOn.split(' ')[0]),
          h('span', record.BeginPrice),
          h(
            'strong',
            {
              style: getFrontColor(currentPrice, beginPrice)
            },
            rate == 'NaN' ? 'N/A' : rate + '%'
          )
        ]);
      }
    },
    {
      title: '当前日期 | 价格 | 涨幅',
      width: 200,
      ellipsis: true,
      resizable: true,
      customRender: ({ record }) => {
        let beginPrice = record.YesterdayPrice;
        let currentPrice = record.CurrentPrice;
        let rate = (((currentPrice - beginPrice) / beginPrice) * 100).toFixed(2);

        return h('div', { class: 'complexs' }, [
          h('span', record.CurrentDate),
          h(
            'span',
            {
              style: getFrontColor(record.CurrentPrice, record.YesterdayPrice)
            },
            record.CurrentPrice
          ),
          h(
            'strong',
            {
              style: getFrontColor(currentPrice, beginPrice)
            },
            rate == 'NaN' ? 'N/A' : rate + '%'
          )
        ]);
      }
    },
    {
      title: '我的购买',
      width: 190,
      ellipsis: true,
      resizable: true,
      customRender: ({ record }) => {
        return record.PurchaseOn ? h('div', { class: 'complexs' }, [h('span', record.PurchaseOn.split(' ')[0]), h('span', record.PurchasePrice), h('span', record.PurchaseQuantity)]) : h('span', '');
      }
    },
    {
      title: '我的收益',
      width: 230,
      fixed: 'right',
      ellipsis: true,
      resizable: true,
      customRender: ({ record }) => {
        if ((record.PurchaseQuantity || 0) <= 0) {
          return h('span', '');
        }

        let beginPrice = record.PurchasePrice;
        let currentPrice = record.CurrentPrice;
        let rate = (((currentPrice - beginPrice) / beginPrice) * 100).toFixed(2);
        let amount = (record.PurchaseQuantity * currentPrice).toFixed(2);

        let htmlAttrs = { style: getFrontColor(currentPrice, beginPrice) };

        return h('div', { class: 'complexs' }, [h('strong', htmlAttrs, amount), h('strong', htmlAttrs, ((currentPrice - beginPrice) * record.PurchaseQuantity).toFixed(2)), h('strong', htmlAttrs, rate + '%')]);
      }
    },
    { title: '', align: 'center', width: 72, fixed: 'right', key: 'op' }
  ];

  const autoHeight = ref(300);
  const shares = ref([]);
  const indexes = ref([]);

  const info = reactive({});
  const showEdit = ref(false);
  const isAddMode = ref(false);

  const countDownNumber = 5;
  const countDown = ref(countDownNumber);
  const countDownVisible = ref(false);

  const tableHeight = computed(() => {
    return $store.state.area.content.height - 135;
  });

  function getRowKey(record) {
    return 'tr' + record.Code;
  }

  function resizeColumn(w, col) {
    col.width = w;
  }

  function getFrontColor(val1, val2) {
    let color = '#909499';

    if (val1 > val2) {
      color = '#ed4014';
    } else if (val1 < val2) {
      color = '#19be6b';
    }

    return { color };
  }

  function ClearDatas() {
    $modal.confirm({
      title: '警告',
      content: '是否确定清理股票数据？',
      onOk() {
        $http.get('/api/shares/clear').then(res => {
          $message.success('清理成功！');

          loadShares();
        });
      }
    });
  }

  function getIndexs() {
    $http.get('/api/shares/index', { hideTip: true }).then(res => {
      indexes.value = res.datas;
    });
  }

  function loadShares() {
    $http.get('/api/shares/list', { hideTip: true }).then(res => {
      shares.value = res.datas;
      totalAmount.value = 0;
      orignalAmount.value = 0;
      incomeAmount.value = 0;

      (shares.value || []).forEach(s => {
        s._loading = false;
        s.children = [];

        let beginPrice = s.PurchasePrice;
        let currentPrice = s.CurrentPrice;

        orignalAmount.value += beginPrice * s.PurchaseQuantity;
        totalAmount.value += currentPrice * s.PurchaseQuantity;
        incomeAmount.value += (currentPrice - beginPrice) * s.PurchaseQuantity;
      });
    });
  }

  function addShare() {
    showEdit.value = true;
    isAddMode.value = true;

    Object.keys(info).forEach(p => (info[p] = ''));

    info.CreatedOn = dayjs();
  }

  function resetShare(info) {
    info.PurchaseOn = null;
    info.PurchasePrice = null;
    info.PurchaseQuantity = null;
  }

  function onEdit(data) {
    showEdit.value = true;
    isAddMode.value = false;

    Object.keys(data).forEach(p => {
      info[p] = data[p];
    });

    info.CreatedOn = dayjs(data.CreatedOn);
    info.PurchaseOn = data.PurchaseOn ? dayjs(data.PurchaseOn) : null;
  }

  function onDetail(data) {
    $router.push(`/share/${data.Code}/Detail?title=${data.Name}`);
  }

  function saveShare() {
    let rawInfo = JSON.parse(JSON.stringify(markRaw(info)));

    rawInfo.PurchasePrice = rawInfo.PurchasePrice || null;
    rawInfo.PurchaseQuantity = rawInfo.PurchaseQuantity || null;
    rawInfo.CreatedOn = dayjs(rawInfo.CreatedOn).format('YYYY-MM-DD HH:mm:ss');
    rawInfo.PurchaseOn = rawInfo.PurchaseOn ? dayjs(rawInfo.PurchaseOn).format('YYYY-MM-DD HH:mm:ss') : null;

    if (!rawInfo.Code) {
      $message.warning('股票编号不能为空！');

      return;
    }

    if (!rawInfo.Name) {
      $message.warning('股票名称不能为空！');

      return;
    }

    if (rawInfo.Code.indexOf('00') == 0 || rawInfo.Code.indexOf('200') == 0 || rawInfo.Code.indexOf('30') == 0) {
      rawInfo.Code = 'sz' + rawInfo.Code;
    } else if (rawInfo.Code.indexOf('60') == 0 || rawInfo.Code.indexOf('900') == 0) {
      rawInfo.Code = 'sh' + rawInfo.Code;
    }

    $http.post('/api/shares/save', rawInfo).then(res => {
      if (res.success) {
        showEdit.value = false;
        $message.success('保存成功！');

        loadShares();
      } else {
        $message.error('出现错误，错误详情：' + res.message);
      }
    });
  }

  function removeShare(code) {
    $modal.confirm({
      title: '提醒',
      content: '是否确定删除该股票？',
      onOk: () => {
        $http.delete(`/api/shares/remove/${code}`).then(res => {
          if (res.success) {
            $message.success('删除成功！');

            loadShares();
          } else {
            $message.error('出现错误，错误详情：' + res.message);
          }
        });
      }
    });
  }

  function onExpand(expanded, record) {
    if (expanded) {
      $eventBus.emit(`reload_${record.Code}`, record.Code);
    }
  }

  onMounted(() => {
    loadShares();
    getIndexs();

    $eventBus.on('windowResizeChanged', client => (autoHeight.value = client.height - 70));

    refresher.start({
      step({ visible, number }) {
        countDown.value = number;
        countDownVisible.value = visible;
      },
      done() {
        loadShares();
        getIndexs();
      }
    });
  });

  onUnmounted(() => {
    refresher.stop();
  });
</script>
<style lang="less">
  .share-card {
    .ant-card-extra {
      position: relative;
      top: -2px;
      right: -15px;

      h3 {
        line-height: 1;
        top: 3px;
        display: inline-block;
        color: red;
        position: relative;
        font-weight: bold;
        vertical-align: middle;
        margin-right: 10px;
      }
    }

    .ant-card-head-title {
      display: flex;
      align-items: center;
      margin-left: -10px;
      padding: 0 !important;
      vertical-align: middle;

      .index {
        font-size: 12px;
        line-height: 12px;
        display: inline-block;
        padding-left: 15px;
        padding-right: 15px;
        border-left: 1px solid #cccccc;

        &:first-of-type {
          margin-left: 15px;
        }

        &:last-of-type {
          padding-right: 0;
        }

        > h4 {
          font-weight: bolder;
          text-align: center;
          color: #000;

          &.rise {
            color: rgb(237, 64, 20);
          }

          &.fall {
            color: rgb(25, 190, 107);
          }
        }

        > div {
          text-align: center;
          margin-top: 5px;

          > b {
            color: rgb(25, 190, 107);
            display: inline-block;
            margin-right: 10px;

            &:last-of-type {
              margin-right: 0;
            }
          }

          &.rise {
            > b {
              color: rgb(237, 64, 20);
            }
          }
        }
      }
    }
  }

  .ant-table-cell,
  .ant-table-cell-content {
    > .complexs {
      width: 100%;
      display: flex;
      align-items: center;

      > span,
      > strong {
        flex: 1;
      }

      > span {
        font-style: italic;

        &:nth-of-type(2) {
          font-style: normal;
          font-weight: bold;
          text-align: left;
          padding-left: 15px;
        }

        &:nth-of-type(3) {
          text-align: right;
          font-style: normal;
        }
      }
    }
  }
</style>
